package org.game;

import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.newdawn.slick.opengl.TextureLoader;

import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL20.glUseProgram;
import static org.lwjgl.opengl.GL20.glDeleteProgram;

public class Game {
	private TextureLoader textureLoader;
	private AudioManager audioManager;
	private static HashMap<String,Integer> shaderMap;
	private static Level level;
	
	/**Static main to be able to create a new copy of this 
	 * class to enable the starting of the game without
	 * the need of an outside java launcher
	 * 
	 * @param args arguments set in place by Java-Arguments
	 */
	public static void main(String[] args){
		new Game();
	}
	/**
	 * The Main class handling everything in the game
	 */
	public Game(){
		init();
	}
	/**
	 * Start the process leading up to the game
	 */
	private void init(){
		initGL();
		initSettings();
		initGame();
		initLevel();
		gameLoop();
	}
	/**
	 * Setup the display for the game
	 */
	private void initGL(){
		try{
			Display.setDisplayMode(new DisplayMode(640,480));
			Display.setVSyncEnabled(true);
			Display.setTitle("Dream");
			Display.create();
		}catch(LWJGLException e){
			e.printStackTrace();
		}
	}
	/**
	 * Setup the settings of the rendering for the 
	 * game.
	 */
	private void initSettings(){
		glEnable(GL_DEPTH_TEST);
		glEnable(GL_TEXTURE_2D);
		glEnable(GL_COLOR_MATERIAL);
		glEnable(GL_LIGHTING);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
		glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
		glShadeModel(GL_SMOOTH);
		glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
	}
	/**
	 * Create the main lines for the game to run
	 */
	private void initGame(){
		textureLoader = new TextureLoader();
		audioManager = new AudioManager();
		shaderMap = new HashMap<String,Integer>();
	}
	/**
	 * Initialize the level and its contents
	 */
	private void initLevel(){
		level = new Level("assets/Levels/main.level");
		int song = AudioManager.loadALBuffer("assets/Audio/foryou.wav");
		int source = AudioManager.createSource(0, 0, 0, song);
		AudioManager.playSource(source);
		System.out.println(level.toString());
	}
	/**Load a specific level
	 * 
	 * @param name the name of the level to load
	 */
	public static void loadLevel(String name){
		level = new Level(IOManager.getFile(name));
	}
	/**
	 * The main loop of the game
	 */
	private void gameLoop(){
		while(!Display.isCloseRequested()){
			renderFrame();
			Display.update();
			Display.sync(60);
		}
		emptyShaders();
		Display.destroy();
		System.exit(0);
	}
	/**
	 * Render the frame of the game
	 */
	private void renderFrame(){
		glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
		
	}
	/** Set the ambient light of the level
	 * 
	 * @param rgba the array holding the RGBA values
	 * @param diffuse if to use Diffuse or not
	 */
	public static void setAmbientLight(float[] rgba,boolean diffuse){
		setAmbientLight(rgba[0],rgba[1],rgba[2],rgba[3],diffuse);
	}
	/** Set the ambient light of the level
	 * 
	 * @param r the red value of the ambient light
	 * @param g the green value of the ambient light
	 * @param b the blue value of the ambient light
	 * @param a the alpha value of the ambient light
	 * @param diffuse whether or not to use diffuse colors
	 */
	public static void setAmbientLight(float r,float g,float b,float a, boolean diffuse){
		FloatBuffer ambientLight = BufferUtils.createFloatBuffer(4);
		ambientLight.put(r).put(g).put(b).put(a).flip();
	
		glLightModel(GL_LIGHT_MODEL_AMBIENT,ambientLight);
		if(diffuse){
			glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
		}else{
			glColorMaterial(GL_FRONT,GL_AMBIENT);
		}
	}
	/**Set the clear color
	 *  
	 * @param rgba the array of color values
	 */
	public static void setClearColor(float[] rgba){
		setClearColor(rgba[0],rgba[1],rgba[2],rgba[3]);
	}
	/** Set the clear color
	 * 
	 * @param r the red value in the clear color
	 * @param g the green value in the clear color
	 * @param b the blue value in the clear color 
	 * @param a the alpha vlaue in the clear color
	 */
	public static void setClearColor(float r,float g,float b,float a){
		glClearColor(r,g,b,a);
	}
	/**Use a specific shader
	 * 
	 * @param id the id of the shader in OpenGL
	 */
	public static void useShader(int id){
		glUseProgram(id);
	}
	/**
	 * Clear all of the space held by the shaders
	 */
	public static void emptyShaders(){
		for(String string: shaderMap.keySet()){
			glDeleteProgram(shaderMap.get(string));
		}
	}
	/**Store a shader in the shader map
	 * 
	 * @param name the name of the shader in the shaderMap
	 * @param id the id of the shader
	 */
	public static void storeShader(String name, int id){
		if(!shaderMap.containsKey(name)){
			shaderMap.put(name, id);
		}else{
			return;
		}
	}
	/**
	 * Output the list of shaders held in the shader map.
	 */
	public static void outputShaders(){
		List<String> shaderNames = new ArrayList<String>();
		for(String string: shaderMap.keySet()){
			shaderNames.add(string);
		}
		System.out.println("SHADER LIST:");
		for(int i=0;i<shaderNames.size();i++){
			System.out.println(shaderNames.get(i) + ":" + shaderMap.get(shaderNames.get(i)));
		}
		System.out.println("END OF SHADER LIST;");
	}
	
}
